/**
 * 
 */
package mpbe.estructura.secciones.hormigon_armado;

/*
 * Este codigo es software libre y se encuentra licenciado 
 * bajo los términos de la Licencia Pública General de GNU versión 3 
 * según se encuentra publicada por la Free Software Foundation.
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Autor: Martin Pablo Bellanca <martin.bellanca@gmail.com>
 * web: http://mpbe.blogspot.com/
 */

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.NumberFormat;
import java.util.Iterator;
import java.util.Vector;

import mpbe.MPBE;
import mpbe.estructura.Material;
import mpbe.estructura.Nodo;
import mpbe.estructura.secciones.hormigon_armado.contornos.SHContorno;
import mpbe.estructura.secciones.hormigon_armado.contornos.SHContornoPorParametros;
import mpbe.geometria.Limites;
import mpbe.geometria.Parametro;
import mpbe.geometria.Punto;

import org.eclipse.swt.widgets.ProgressBar;


/**
 * @author mpbe
 *
 */
public class Hormigon_armado_flexion {
	private Hormigon_armado ha = null;
	private SHCargas cargas = null;
	private SHContornos contornos = null;
	private SHGrupos grupos = null;
	private Material acero = null;
	private Material hormigon = null;
	
	private String strError = null;
	
	
	//------------------------------------
	// Constructores
	//------------------------------------
	public Hormigon_armado_flexion()
	{
		ha = new Hormigon_armado();
		cargas = new SHCargas();
		contornos = new SHContornos();
		grupos = new SHGrupos();
		acero = new Material();
		hormigon = new Material();
	}
	
	public Hormigon_armado_flexion(Hormigon_armado seccion)
	{
		this();	
		setHA(seccion);
	}
	
	
	//------------------------------------
	// Getters and Setters
	//------------------------------------
	public void setHA(Hormigon_armado ha) {
		this.ha = ha;
		// PODRIA CONVENIR COLOCAR ESTAS 3 EN Verificar_Seccion
		ha.cargas.copyInto(cargas.getCargas());
		ha.contornos.copyInto(contornos.getContornos());
		ha.grupos.copyInto(grupos.getGrupos());
		ha.getGenerales().acero.copyInto(acero);
		ha.getGenerales().hormigon.copyInto(hormigon);
	}
	
	public String getStrError() {
		return strError;
	}
	
	public SHFlexion getResultados()
	{
		SHFlexion res = new SHFlexion();
		ha.getResultados().copyInto(res);
		return res;
	}
	
	
	//------------------------------------
	// Funciones de Calculo
	//------------------------------------
	public boolean verificar_seccion(ProgressBar progress) throws IOException{
		// TODO agregar descripcion de errores en strError
		strError = "";
		
		progress.setSelection(0);
		
		// Abre el Archivo DiHA_MN.log
		File outputFile = new File("DiHA_MN.log");
		PrintWriter outlog = new PrintWriter(outputFile);
		
		//if (!resultados.recalcular) return true;
		/*if (!resultados.calculo_habilitado) {
			outlog.println("Calculo cancelado por no estar habilitado");
			outlog.close();
			return false;
		}*/
		
		// Funcion de redondeo
		NumberFormat nf = NumberFormat.getInstance();
		nf.setMaximumFractionDigits(4); //Establecemos el numero de decimales
		nf.setMinimumFractionDigits(4);
		NumberFormat nf1 = NumberFormat.getInstance();
		nf1.setMaximumFractionDigits(4);
		nf1.setMinimumIntegerDigits(6);
		
		SHGenerales generales = ha.getGenerales();
		outlog.println("Deformacion de fluencia del acero: "+nf.format(generales.acero.Ese));
		outlog.println("Intervalo de calculo: "+contornos.getIntervaloCalculo());
		// Unidades de calculo
		outlog.println("Unidad de Long.: "+generales.uLongitud.Designacion+" : "+generales.uLongitud.Coef);
		outlog.println("Unidad de Fuerza: "+generales.uFuerza.Designacion+" : "+generales.uFuerza.Coef);
		// Br y Bs
		double br = generales.uFuerza.convertir_local(generales.hormigon.Bf);
		br = generales.uLongitud.convertir_local(br, -2);
		outlog.println("Br: "+br);
		double bs = generales.uFuerza.convertir_local(generales.acero.Bf);
		bs = generales.uLongitud.convertir_local(bs, -2);
		outlog.println("Bs: "+bs);
		
		// variables internas de calculo
		SHFlexion res1 = new SHFlexion();
		SHFlexion res2 = new SHFlexion();
		SHFlexion res3 = new SHFlexion();
		long MNcomp = 0; // MN de comparacion en la iteracion
		double Viter; // variable de iteracion
		int canIter = 0;
		double av100 = 0;
		double av = 0;

		// Obtiene la carga de calculo
		SHCarga carga = cargas.get_Carga_Activa();
		// si Ms< espeja la seccion
		if (carga.Ms<0) {
			contornos.mod_InvertirV();
			grupos.mod_InvertirV();
			cargas.mod_InvertirV();			
		}
		outlog.println("");
		outlog.println("Cargas activas:");
		outlog.println("  Ns ="+carga.Ns);
		outlog.println("  Ms ="+carga.Ms);
		
		//Imprime en el log la seccion de hormigon
		outlog.println("");
		outlog.println("Contornos activos de la sección:");
		Iterator<SHContorno> ic = contornos.iterator();
		SHContorno co = new SHContorno();
		do { 
			co = ic.next();
			if (co.activo) {
				outlog.println("  Designación: "+co.designacion);
				SHContornoPorParametros cpp = co.parametros;
				outlog.println("    Tipo de contorno: "+cpp.getDesignacion());
				int ii = 0;
				while (cpp.getParametro(ii).designacion!="fin") {
					outlog.println("    "+cpp.getParametro(ii).designacion+": "+ cpp.getParametro(ii).valor);
					ii ++;
				}
				outlog.println("  Coordenadas de vertices:");
				for (Punto pp : co.nodos)
					outlog.println("    ("+pp.getX()+";"+pp.getY()+")");
			}
		} while (ic.hasNext());
		
		//Imprime en el log la armadura
		outlog.println("");
		outlog.println("Armadura de la sección:");
		Iterator<SHGrupo_de_Barras> gr = grupos.iterator();
		SHGrupo_de_Barras gb = new SHGrupo_de_Barras();
		do {
			gb = gr.next();
			if (gb.activo) {
				outlog.println("  Designación: "+gb.designacion);
				for (Barra_Redonda bb : gb.barras) 
					outlog.println("    "+bb.diametro+" ("+bb.posX+";"+bb.posY+")");
			}
		} while (gr.hasNext());
		
		// Encabezado de planilla de archivo log
		outlog.println("");
		outlog.println("\tMN\t|Zona\t|\tEb1\t|\tEs2\t|\tX\t|\tZu\t|\tDbu\t|\ta\t|\tNu\t|\tMu");
		
		// calcula Ymax Ymin, d y h
			// h: calculado como distancia de fibra comprimida a la barra mas alejada inferior
		Limites extremos = contornos.getLimitesV();
		double d = Math.abs(extremos.max - extremos.min);
		double h = 0, hh=0;
		SHGrupo_de_Barras GB;
		GB = grupos.get(0); 
		h = GB.getYmin();
		for (int gg=0; gg<grupos.size(); gg++){
			GB = grupos.get(gg);
			if (GB.activo) {
				hh = GB.getYmin();
				if (hh<h) h=hh;
			}
		}
		h = extremos.max-h;
		
		// Define la recta ultima de inicio
		// en el limite de las zonas 2 y 3
		res1.recta_ultima.setLimiteDeZona(23, d, h, ha.getMaterial(), ha.getGenerales().acero);
		calc_MN(res1, carga, h);
		canIter++;
		// avance del calculo
		av100 = Math.abs((int)res1.coef_seguridad.MN*1000);
		av = 0;
		
		
		outlog.println("****** Recta Ultima en limite de zonas 2-3 ******");
		printlog(outlog, res1, nf, nf1);
		
		if (res1.coef_seguridad.MN < 0) {
			// SI puede ser zona 1 o 2 ******
			res2.recta_ultima.setLimiteDeZona(12, d, h, ha.getMaterial(), ha.getGenerales().acero);
			calc_MN(res2, carga, h);
			canIter++;
			// avance del calculo
			av = 100*(av100-Math.abs(res2.coef_seguridad.MN*1000))/av100;
			progress.setSelection((int)av);
			
			outlog.println("****** Recta Ultima en limite de zonas 1-2 ******");
			printlog(outlog, res2, nf, nf1);
			
			if (res2.coef_seguridad.MN < 0) {
				// La recta ultima esta en zona 1 ******
				res3.recta_ultima.setLimiteDeZona(1, d, h, ha.getMaterial(), ha.getGenerales().acero);
				res3.recta_ultima.Zona = 1;
				
				outlog.println("****** Recta Ultima en Zona 1. Itera sobre Eb1 ******");
				
				/*strError = "La recta última se encuentra en zona 1. No puede verificarse por este método";
				outlog.println("La recta ultima se encuentra en zona 1. No puede verificarse por este metodo");
				outlog.close();
				return false;*/
			} else {
				// La recta ultima esta en zona 2 ******
				res3.recta_ultima.setLimiteDeZona(12, d, h, ha.getMaterial(), ha.getGenerales().acero);
				res3.recta_ultima.Zona = 2;
				
				outlog.println("****** Recta Ultima en Zona 2. Itera sobre X ******");
	
			} 
		} else {
			// Puede ser zona 34 o 5 ******
			res2.recta_ultima.setLimiteDeZona(45, d, h, ha.getMaterial(), ha.getGenerales().acero);
			calc_MN(res2, carga, h);
			canIter++;
			// avance del calculo
			if (Math.abs(res2.coef_seguridad.MN*1000)>av100) av100 = Math.abs(res2.coef_seguridad.MN*1000);
			av = 100*(av100-Math.abs(res2.coef_seguridad.MN*1000))/av100;
			progress.setSelection((int)av);
			
			outlog.println("****** Recta Ultima en limite de zonas 3,4 o 5 ******");
			printlog(outlog, res2, nf, nf1);
			
			if (res2.coef_seguridad.MN < 0) {
				// La recta ultima esta en zona 3 o 4 ******
				res3.recta_ultima.setLimiteDeZona(23, d, h, ha.getMaterial(), ha.getGenerales().acero);
				res3.recta_ultima.Zona = 34;
				
				outlog.println("****** Recta Limite en Zona 3 o 4. Itera sobre X ******");
			} else {
				// La recta ultima puede estar en zona 5 ******
				
				res3.recta_ultima.setLimiteDeZona(5, d, h, ha.getMaterial(), ha.getGenerales().acero);
				res3.recta_ultima.Zona = 5;
				
				outlog.println("****** Recta Límite en Zona 5. Itera sobre Es2 ******");
			}
		}
		
		// Definida la zona se itera dentro de esta para encontrar MN=0
		calc_MN(res3, carga, h);
		// avance del calculo
		av = 100*(av100-Math.abs(res3.coef_seguridad.MN*1000))/av100;
		progress.setSelection((int)av);

		printlog(outlog, res3, nf, nf1);
		
		while (((long)(res3.coef_seguridad.MN * 100)!=0)&&(MNcomp != (long)(res3.coef_seguridad.MN * 1000))) {
			MNcomp = (long)(res3.coef_seguridad.MN*1000);
			switch (res3.recta_ultima.Zona) {
			case 1: // Zona 1 ****** Itera sobre Eb1
				Viter = (res2.coef_seguridad.MN*res1.recta_ultima.Eb1-res1.coef_seguridad.MN*res2.recta_ultima.Eb1)/(res2.coef_seguridad.MN-res1.coef_seguridad.MN);
				res3.recta_ultima.Eb1 = Viter;
				res3.recta_ultima.X = -h/(res3.recta_ultima.Es2/res3.recta_ultima.Eb1-1);
				
				if ((res3.recta_ultima.Eb1>acero.El)||(res3.recta_ultima.Eb1<0)) { //El=5%o
					strError = "La recta última salio de la zona 1. No puede verificarse.";
					outlog.println("La recta última salio de la zona 1. No puede verificarse.");
					outlog.close();
					return false;
		    	}
				break;
			case 2: // Zona 2 ****** Itera sobre X
				Viter = (res2.coef_seguridad.MN*res1.recta_ultima.X-res1.coef_seguridad.MN*res2.recta_ultima.X)/(res2.coef_seguridad.MN-res1.coef_seguridad.MN);
				res3.recta_ultima.X = Viter;
				res3.recta_ultima.Eb1 = res3.recta_ultima.Es2/(1-h/Viter);
				
				if ((res3.recta_ultima.Eb1>0)||(res3.recta_ultima.Eb1<hormigon.El)) { //El=-3.5%o
					strError = "La recta última salio de la zona 2. No puede verificarse.";
					outlog.println("La recta última salio de la zona 2. No puede verificarse.");
					outlog.close();
					return false;
		    	}
				break;
			case 34: // Zona 3 4 ****** Itera sobre X
				Viter = (res2.coef_seguridad.MN*res1.recta_ultima.X-res1.coef_seguridad.MN*res2.recta_ultima.X)/(res2.coef_seguridad.MN-res1.coef_seguridad.MN);
				res3.recta_ultima.X = Viter;
				res3.recta_ultima.Es2 = res3.recta_ultima.Eb1*(1-h/Viter); 
				
				if ((res3.recta_ultima.Es2>acero.El)||(res3.recta_ultima.Es2<res3.recta_ultima.getEslim45(d, h, ha.getMaterial().El))) { //El=5%o
					strError = "La recta última salio de la zona 3 4. No puede verificarse.";
					outlog.println("La recta última salio de la zona 3 4. No puede verificarse.");
					outlog.close();
					return false;
		    	}	
				break;
			case 5: // Zona 5 ****** Itera sobre Es2
				Viter = (res2.coef_seguridad.MN*res1.recta_ultima.Es2-res1.coef_seguridad.MN*res2.recta_ultima.Es2)/(res2.coef_seguridad.MN-res1.coef_seguridad.MN);
				if (Viter<-2) Viter = -1.9999;
				res3.recta_ultima.Es2 = Viter;
				res3.recta_ultima.Eb1 = res3.recta_ultima.cg * (hormigon.Ese - res3.recta_ultima.Es2) / (h - res3.recta_ultima.cg) + hormigon.Ese;
				res3.recta_ultima.X = calc_X(res3, h);
				
				if ((res3.recta_ultima.Es2 > res3.recta_ultima.getEslim45(d, h, ha.getMaterial().El))||(res3.recta_ultima.Es2 < hormigon.Ese)) { 
					strError = "La recta última salio de la zona 5. No puede verificarse.";
					outlog.println("La recta última salio de la zona 5. No puede verificarse.");
					outlog.close();
					return false;
				}
				
				break;
			}

			calc_MN(res3, carga, h);
			canIter++;
			// avance del calculo
			av = 100*(av100-Math.abs(res3.coef_seguridad.MN*1000))/av100;
			progress.setSelection((int)av);

			printlog(outlog, res3, nf, nf1);

			if (((res3.coef_seguridad.MN>0)&&(res2.coef_seguridad.MN<0))
					||((res3.coef_seguridad.MN<0)&&(res2.coef_seguridad.MN>0))) 
				res3.copyInto(res1);
			else
				res3.copyInto(res2);

		//} while (MNcomp != (long)(res3.coef_seguridad.MN * 1000));
		} 
	
		// define entre zona 3 o 4
		if (res3.recta_ultima.Zona==34) {
			if (res3.recta_ultima.Es2>generales.acero.Ese) 
				res3.recta_ultima.Zona = 3;
			else
				res3.recta_ultima.Zona = 4;
		}
		// Calcula el Coef de Seg Reglamentario
		res3.coef_seguridad.Reglamentario = 2.1 - res3.recta_ultima.Es2 * 35 / 300;
		if (res3.recta_ultima.Es2>3) res3.coef_seguridad.Reglamentario = 1.75;
		if (res3.recta_ultima.Es2<0) res3.coef_seguridad.Reglamentario = 2.1;
		// calcula coef seg de M y N
		if (carga.Ms!=0) 
			res3.coef_seguridad.M = res3.esfuerzo_ultimos.Mu/Math.abs(carga.Ms); 
		else 
			res3.coef_seguridad.M = 0;
		if (carga.Ns!=0) 
			res3.coef_seguridad.N = res3.esfuerzo_ultimos.Nu/carga.Ns; 
		else 
			res3.coef_seguridad.N = 0;
		
		outlog.println("------------------------------------------------------------------------");
		outlog.println("Zona: "+res3.recta_ultima.Zona);
		outlog.println("Coeficiente de seguridad Reglamentario: "+nf.format(res3.coef_seguridad.Reglamentario));
		outlog.println("Coeficiente de seguridad de Mtos: \t"+nf.format(res3.coef_seguridad.M));
		outlog.println("Coeficiente de seguridad de Normal: \t"+nf.format(res3.coef_seguridad.N));
		outlog.println("Cantidad de iteraciones realizadas= \t"+canIter);
		outlog.close();
		SHFlexion resultados = ha.getResultados();
		res3.copyInto(resultados);
		progress.setSelection(100);
		resultados.recalcular = false;
		return true;
		
/*		cancela:
		q = "Se produjo un error en el proceso de calculo." + Chr$(13)
		q = q + "Controle si los datos estan correctamente ingresados."
		MsgBox (q)*/
		
	}

	private void calc_Dbu(SHFlexion res) {
		FuncionDbu fDBu = new FuncionDbu(); //define e inicializa la funcion para el calculo
		Limites LM = contornos.getLimitesV();
		fDBu.Ymin=LM.min;
		fDBu.Ymax=LM.max;
		res.recta_ultima.copyInto(fDBu.RU);
		SHGenerales generales = ha.getGenerales();
		fDBu.Br=generales.uFuerza.convertir_local(generales.hormigon.Bf);
		fDBu.Br= generales.uLongitud.convertir_local(fDBu.Br, -2);
		fDBu.Dbu=0;
		fDBu.Mto=0;
		fDBu.Ese=hormigon.Ese;
		
		// Verifica que no este en la zona 1
		if ((res.recta_ultima.Zona==1)||(res.recta_ultima.X<0)) {  //en original RecLim.X==0 revisar
			res.esfuerzo_ultimos.a = 0;
			res.esfuerzo_ultimos.Dbu = 0;
			res.esfuerzo_ultimos.Mu = 0;
		} 
		else {
			boolean limiteInf = true;
			if ((LM.max-fDBu.RU.X)<LM.min) 
				limiteInf = false; // zona 5 integra toda la seccion
			contornos.areaIntegrada(fDBu, false, 0, limiteInf, LM.max-fDBu.RU.X);
			res.esfuerzo_ultimos.Dbu=fDBu.Dbu;
			if (fDBu.Dbu==0) 
				res.esfuerzo_ultimos.a= 0;
			else 
				res.esfuerzo_ultimos.a=fDBu.Mto/fDBu.Dbu; // al eje de referencia
				//res.esfuerzo_ultimos.a=LM.max-(fDBu.Mto/fDBu.Dbu); // a la fibra mas comprimida
		};
		res.esfuerzo_ultimos.Mu = -fDBu.Mto;
		
	}
	
	private double calc_Zu(double area, double posY, SHFlexion res, double h) {
		Limites extremos = contornos.getLimitesV();
		RectaUltima RecLim = res.recta_ultima;
		double Esi, bb;
		SHGenerales generales = ha.getGenerales();
		if (h!=0) 
			Esi=(RecLim.Es2-RecLim.Eb1)*(extremos.max-posY)/h+RecLim.Eb1; 
		else 
			Esi=0;
		double bs = generales.uFuerza.convertir_local(generales.acero.Bf);
		bs = generales.uLongitud.convertir_local(bs, -2);
		if (Math.abs(Esi)>generales.acero.Ese) 
			bb=bs; 
		else 
			bb = Esi*bs/generales.acero.Ese;
		if ((Esi<0)&&(bb>0)) bb=-bb;
		return area*bb;
	}
	
	private double calc_X (SHFlexion res, double h) {
		RectaUltima RU = res.recta_ultima;
		double X;
		if (RU.Eb1==RU.Es2) {
			if (RU.Zona==1) 
				X = -999999;
			else
				X = 999999;
		}
		else
			X = RU.Eb1*h/(RU.Eb1-RU.Es2);
		return X;
	}
	
	private boolean calc_MN(SHFlexion res, SHCarga carga, double h) {
		EsfuerzosUltimos EsfUlt = res.esfuerzo_ultimos;
		
		calc_Dbu(res);
		
		// Calcula Zu y Mu de Zu
		EsfUlt.Zu = 0;
		SHGrupo_de_Barras grupo = null;
		Barra_Redonda BR = null;
		double zu = 0, Mzu = 0, areaBR;
		for (int gg=0; gg<grupos.size(); gg++){
			grupo = grupos.get(gg);
			if (grupo.activo) {
				for (int ii=0; ii<grupo.barras.size(); ii++){
					BR = grupo.barras.get(ii);
					areaBR = ha.getGenerales().uLongitud.convertir_local(BR.getArea()/100, 2);
					zu = calc_Zu(areaBR, BR.posY, res, h);
					EsfUlt.Zu += zu;
					Mzu += zu * BR.posY;
					//EsfUlt.Mu -= zu * BR.posY;
				}
			}
		}
		
		EsfUlt.Nu = EsfUlt.Zu + EsfUlt.Dbu;
		EsfUlt.Mu -= Mzu;
		EsfUlt.z = Mzu/EsfUlt.Zu;
		
		res.coef_seguridad.MN = Math.abs(carga.Ms)*EsfUlt.Nu-EsfUlt.Mu*carga.Ns;
		return true;
	}



	/*private double redondear(double valor){
		double decRedondeo = ha.getGenerales().uLongitud.Coef*100;
		return ((double)Math.round(valor*decRedondeo)/decRedondeo);
	}*/

	private void printlog(PrintWriter outlog, SHFlexion res, NumberFormat nf, NumberFormat nf1) {
		outlog.println(nf1.format(res.coef_seguridad.MN)+"\t| "+res.recta_ultima.Zona+"\t| "
				+nf.format(res.recta_ultima.Eb1)+"\t| "+nf.format(res.recta_ultima.Es2)+"\t| "
				+nf.format(res.recta_ultima.X)+"\t| "+nf.format(res.esfuerzo_ultimos.Zu)+"\t| "
				+nf.format(res.esfuerzo_ultimos.Dbu)+"\t| "+nf.format(res.esfuerzo_ultimos.a)+"\t| "
				+nf.format(res.esfuerzo_ultimos.Nu)+"\t| "+nf.format(res.esfuerzo_ultimos.Mu));
	}
	
}
